package com.myBlog.controller;

import com.alibaba.fastjson2.JSONObject;
import com.myBlog.config.ProjectConfigProperties;
import com.myBlog.utils.JsonUtil;
import lombok.Data;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

@Slf4j
@RestController
@RequestMapping("/admin")
public class UploadController {

    @Value("${upload.path}")
    private String uploadPath;

    @Value("${upload.visitRoot}")
    private String visitRootPath;
    @Autowired
    private ProjectConfigProperties properties;


    private String saveFile(MultipartFile file) throws IOException {
        if(file.getSize()==0){
            log.info("文件名 {} 的文件大小为0，跳过上传", file.getOriginalFilename());
            return "";
        }
        String dateStr = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String newFileName =  String.join(properties.upload_file_dot , new String[]{ dateStr,String.valueOf((int) (Math.random()*1000)), file.getOriginalFilename() });
        new File(uploadPath).mkdirs();

        String filePath = uploadPath + '/' + newFileName;
        FileOutputStream fileOutputStream = new FileOutputStream(filePath);
        fileOutputStream.write(file.getBytes());

        fileOutputStream.flush();
        fileOutputStream.close();
        log.info("文件 {} 上传到路径 {} 成功, 新的名称为 {}",file.getOriginalFilename(), uploadPath, newFileName );
        return  visitRootPath+newFileName;
    }

    @PostMapping("/upload-single")
    public JSONObject uploadSingleFile(@RequestParam("file") MultipartFile file){
        try {
            return JsonUtil.ok_with_Object("path", this.saveFile(file));
        } catch (IOException e) {
            log.error("单文件文件上传接口失败", e);
            return JsonUtil.error_info("上传失败");
        }
    }

    @PostMapping("/upload-multiple")
    public JSONObject uploadMultipleFiles(@RequestParam("files") MultipartFile[] files){
        List<String> list = new LinkedList<>();
        for(MultipartFile file : files){
            try {
                list.add(this.saveFile(file));
            } catch (IOException e) {
                log.error("多文件文件上传接口失败", e);
                return JsonUtil.error_info("上传失败");
            }
        }

        log.info("多文件上传成功");
        return JsonUtil.ok_with_Object("paths", list);
    }

    @Data
    @ToString
    private class FileItem{
        String name;
        String path;
        String size;
        String date;

        Date date_origin;
        public FileItem(String name, String path, String size, long msCount) {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            this.name = name;
            this.path = path;
            this.size = size;
            this.date_origin = new Date(msCount);
            this.date =  dateFormat.format(this.date_origin);
        }
    }

    private static long KB_bytes = 1024;
    private static long MB_bytes = KB_bytes*1024;
    private static long GB_bytes = MB_bytes*1024;

    private String getFileSize(File file){
        long fileSize = file.length();
        if(fileSize<KB_bytes){
            return fileSize+" bytes";
        }
        DecimalFormat df = new DecimalFormat("#.00");
        if(fileSize<MB_bytes){
            double num = (double) file.length()/KB_bytes;
            return df.format(num)+" KB";
        }
        if(fileSize<GB_bytes){
            double num = (double) file.length()/MB_bytes;
            return df.format(num)+" MB";
        }

        double num = (double) file.length()/GB_bytes;
        return df.format(num)+" GB";
    }

    @PostMapping("/fileList")
    public JSONObject getFileList(@RequestBody JSONObject params){
        int pageNum = Objects.requireNonNullElse( params.getInteger("current"), 1);
        int pageSize = Objects.requireNonNullElse( params.getInteger("pageSize"), 10);
        boolean dateDesc = Objects.requireNonNullElse( params.getBoolean("dateDesc"), true);

        // 读取文件全部列表
        LinkedList<FileItem> resultList = new LinkedList<>();
        File uploadFolder = new File(uploadPath);
        uploadFolder.mkdirs();

        // 规定： 上传路径到直接子目录存储文件，不能再创建子文件夹存储
        File[] listFiles = uploadFolder.listFiles();
        for(File file : listFiles){
            if(file.isFile()){
                String visitPath = visitRootPath+file.getName();
                resultList.add(new FileItem(file.getName(), visitPath, this.getFileSize(file), file.lastModified()));
            }
        }

        // 排序：默认最近修改在前
        if(dateDesc){
            resultList.sort((file1,file2)->file1.date_origin.getTime()>file2.date_origin.getTime()?-1:1 );
        }else {
            resultList.sort((file1,file2)->file1.date_origin.getTime()<file2.date_origin.getTime()?-1:1 );
        }

        JSONObject result = JsonUtil.ok_with_Data(
                resultList.subList((pageNum - 1) * pageSize,
                 resultList.size()>=pageNum * pageSize? pageNum * pageSize : resultList.size() )
        );
        result.put("total", resultList.size());
        return result;
    }

    @PostMapping("/deleteFile")
    public JSONObject deleteFile(@RequestBody JSONObject params){
        String totalFilePath = Objects.requireNonNull( params.getString("path"), "删除的文件路径不得为空");
        String fileName = totalFilePath.replace(visitRootPath, "");

        new File(uploadPath).mkdirs();
        log.info("将要删除的文件 路径为 {}, 原本参数是 {}, 删除的路径是 {}", fileName, totalFilePath, uploadPath +'/'+ fileName);
        File delFile = new File(uploadPath +'/'+ fileName);
        if(delFile.exists()&&delFile.isFile()&&delFile.delete()){
             return JsonUtil.ok_info("文件删除成功");
        }

        return  JsonUtil.error_info("文件删除失败: 请检查文件是否存在，或文件是否为 非文件夹");
    }
}
